package com.hongxin.nw.netty.down;

import com.alibaba.fastjson.JSONObject;
import com.hongxin.nw.netty.config.ApplicationContextProvider;
import com.hongxin.nw.netty.model.Transfer;
import com.hongxin.nw.netty.model.analysis.info.Mrena1_1;
import com.hongxin.nw.netty.model.packing.ASDUcsdna1;
import com.hongxin.nw.netty.model.packing.info.Csdna1_2;
import com.hongxin.nw.netty.mq_info.domain.AuthRequest;
import com.hongxin.nw.netty.server.AuthService;
import com.hongxin.nw.netty.utils.FieldPack;
import com.hongxin.nw.netty.utils.MyJson;
import com.hongxin.nw.netty.utils.pools.AsduStartPools;
import com.hongxin.nw.netty.utils.pools.CodeTypePools;
import com.hongxin.nw.netty.values.StaticValue;
import com.hongxin.nw.netty.values.TypeIdentif;
import lombok.extern.slf4j.Slf4j;

/**
 * @remark A.10 充电鉴权下行数据
 * @author: GuoXiaolin
 * @date 2019/6/21 17:31
 * @Version 1.0
 * @Descibe
 */
@Slf4j
public class ChargeAuthReq implements  IChannelRequest {

    @Override
    public String doPacking(Transfer transfer) throws Exception {

        Csdna1_2 csdna1_2 = new Csdna1_2();
        String hold; //..

        AuthService authService = ApplicationContextProvider.getBean(AuthService.class);
        String code = transfer.getCode();
        Mrena1_1 dataItem =  (Mrena1_1)transfer.getObj();
        AuthRequest authRequest = new AuthRequest();
        authRequest.setUserId(dataItem.getPhcNum());
        authRequest.setAuthenticationMode("0");
        authRequest.setBalance(dataItem.getCardMoney());
        authRequest.setInterfaceNumber(String.valueOf(Integer.parseInt(dataItem.getCharge_inter_identify())+1));
        authRequest.setMachineId(dataItem.getCo());
        authRequest.setNumberPlate(dataItem.getVin());
        authRequest.setUpdateBalance("0");
        MyJson httpRes = authService.auth(authRequest);//请求鉴权数据,计费模型数据

        //***************** start  判断鉴权是否成功 *****************
        String bz = StaticValue.VERIFY_SUCCESS; //成功,失败
        String fail = "0000"; //失败原因
        if (httpRes.getCode() == StaticValue.SUCCESS){
            int responseCode = httpRes.getJobData().getIntValue("responseCode");
            int balanceIndication = httpRes.getJobData().getIntValue("balanceIndication");
            int cc = caseReason(responseCode, balanceIndication);
            if(cc != 0){
                bz = StaticValue.VERIFY_FAIL;
                fail = getResponseCodeReson(cc);
            }
        }else{
            bz = StaticValue.VERIFY_FAIL;
            fail = getCodeReason(httpRes.getCode());
        }
        //***************** end  判断鉴权是否成功 *****************

        log.info("鉴权结果:{}[{}({})]", bz, checkInfo(fail),fail);

        if (StaticValue.VERIFY_SUCCESS.equals(bz)){
            //封装计费策略
            JSONObject hj = httpRes.getJobData();
            JSONObject json = hj.getJSONObject("policy");
            Transfer transfer1 = new Transfer(code, null, json,
                    TypeIdentif.M_DEFAULT.getInt(), CodeTypePools.getCodeType(code),
                    Transfer.noNeedRecord, Transfer.noNeedMq, null);

            BillingReq2 billingReq = new BillingReq2();
            String br = billingReq.doPacking(transfer1);
            String vin = dataItem.getVin();
            if (dataItem.getVin().trim().isEmpty()){
                vin =  "TestVin123456790";
            }

            //鉴权下行数据
            csdna1_2 = csdna1_2.setCo(code)
                    .setChargeIdentify(dataItem.getCharge_inter_identify())//枪号
                    .setPhysicsNum(dataItem.getPhcNum())//卡号
                    .setA(vin)//vin
                    .setBillingModel(dataItem.getBilling_model_id())//计费id
                    .setYe(Double.parseDouble(hj.getString("balance")))//余额
                    .setSuccessIdentify(bz)//成功标识,1:成功,0:失败
                    .setFailIdentify(fail)//失败原因,成功时置为0
                    .setSyLc(0.00)
                    .setKcDl(0.00)
                    .setSyCs(0.00);
            hold = csdna1_2.packing() + StaticValue.JF + br;
        }else {
            csdna1_2 = csdna1_2.setCo("0")
                    .setChargeIdentify("0")//枪号
                    .setPhysicsNum("0")//卡号
                    .setA("0")//vin
                    .setBillingModel("0")//计费id
                    .setYe(0.00)//余额
                    .setSuccessIdentify(bz)//成功标识,1:成功,0:失败
                    .setFailIdentify(fail)//失败原因,成功时置为0
                    .setSyLc(0.00)
                    .setKcDl(0.00)
                    .setSyCs(0.00);
            hold = csdna1_2.packing();
        }

        ASDUcsdna1 mm = new ASDUcsdna1();
        mm.setLogType(String.valueOf(TypeIdentif.RECORD_CHARGE_AUTH.getInt()));
        mm.setSendData(hold);

//        as.setType(TypeIdentif.IDENTIFY_C_SD_NA_1.getInt());
//        as.setCot(TypeIdentif.COT_UNKNOWN_COT.getInt());
//        as.setStaadr(AsduStartPools.getAsduStart(code).getStatAddress());
//        as.setInfoadr(Integer.parseInt(dataItem.getCharge_inter_identify()));
//        as.setVsq(0, StaticValue.SQ0);


        String as = FieldPack.packASDU(TypeIdentif.IDENTIFY_C_SD_NA_1.getInt(),
                TypeIdentif.COT_UNKNOWN_COT.getInt(),
                AsduStartPools.getAsduStart(code).getStatAddress(),Integer.parseInt(dataItem.getCharge_inter_identify()),
                0, StaticValue.SQ0);

        String data = as + mm.getHexData();

//        APCI ac = new APCI();
//        ac.setIdentifyStart(TypeIdentif.IDENTIFY_START.getInt())
//                .setApduLength(as.getHexData().length()/2)
//                .setContarea(TypeIdentif.FORMAT_I.getStr(),StaticValue.U_START_V);
//
//        return ac.getHexData() + as.getHexData();

        String ac = FieldPack.packAPCI(data.length(), TypeIdentif.FORMAT_I.getStr(), StaticValue.U_START_V);
        return ac + data;
    }


    private int caseReason(int responseCode,int balanceIndication){
        log.info("鉴权卡信息 responseCode:{},balanceIndication:{}",responseCode, balanceIndication);
        //responseCode
        //* 0：有效账户
        //* 1：非法账户
        //* 2--该卡已经在另外一个充电桩上充电，不允许一张卡同时在多台充电桩上充电
        //* 3：VIN号鉴权失败，数据未绑定
        //* 4：车牌鉴权失败，数据未绑定
        //* 5:桩开放时段内此卡无权限

        //balanceIndication
        //* 0-余额不足
        //* 1-余额充足
        //* 2-余额校验有误，需要把后台余额写入卡
        //* 3-余额校验有误，不允许充电

        int c = 0;
        if (responseCode == 0 && balanceIndication==0) {
            c = 1;
        }
        if (responseCode == 0 && balanceIndication==2){
            c = 2;
        }
        if (responseCode == 0 && balanceIndication==3){
            c = 3;
        }
        if (responseCode==1){
            c = 11;
        }
        if (responseCode==2){
            c = 12;
        }
        if (responseCode==3){
            c = 13;
        }
        if (responseCode==4){
            c = 14;
        }
        if (responseCode==5){
            c = 15;
        }
        return c;
    }

    private String getResponseCodeReson(int c){//注意此处业务系统经常会有难以解决的bug返回,,,此处亟待优化
        String reason;
        switch (c){
            case 1://余额不足
                reason = "5003";
                break;
            case 2://余额校验有误，需要把后台余额写入卡
                reason = "5003";
                break;
            case 3://账户不余额校验有误，不允许充电
                reason = "5003";
                break;
            case 11://非法账户
                reason = "5001";
                break;
            case 12://该卡已经在另外一个充电桩上充电，不允许一张卡同时在多台充电桩上充电
                reason = "5004";
                break;
            case 13://VIN号鉴权失败，数据未绑定
                reason = "5015";
                break;
            case 14://车牌鉴权失败，数据未绑定
                reason = "5015";
                break;
            case 15://桩开放时段内此卡无权限
                reason = "5007";
                break;
            default://成功
                reason = "0000";
                break;
        }
        return reason;
    }

    private String getCodeReason(int c){//注意此处业务系统经常会有难以解决的bug返回,,,此处亟待优化
        String reason;
        switch (c){
            case 16016://该会员卡已冻结或已失效,
                reason = "5001"; //5001:无效卡号
                break;
            case 16017://该会员卡已冻结或已失效,
                reason = "5001"; //5001:无效卡号
                break;
            case 16004://账户不能为空,
                reason = "5016";//5016:无效账户状态
                break;
            case 16005://未找到对应账户,
                reason = "5016";//5016:无效账户状态
                break;
            case 16007://获取电站ID失败,
                reason = "5001";
                break;
            case 16009://获取计费策略失败
                reason = "5001";
                break;
            case 16020://非法账户
                reason = "5001";//5001:无效卡号
                break;
            case 16028://账户余额不足
                reason = "5003";//5003:余额不足
                break;
            case 16021://您有充电订单正在充电
                reason = "5004";//5004:卡锁住
                break;
            case 16023://VIN号鉴权失败
                reason = "5015";//5015:无效车状态
                break;
            case 16024://余额校验有误,需要把后台余额写入卡
                reason = "5016";//5016:无效账户状态
                break;
            case 16025://余额校验有误,不允许充电
                reason = "5011";//5011:套餐余额不足
                break;
            case 16026://车牌鉴权失败
                reason = "5015";//5015:无效车状态
                break;
            case 16027://桩开放时段内此卡无权限
                reason = "5007";//5007:无效卡
                break;
            default: //代理接口异常 ,获取计费策略失败,
                reason = "5099";//5099:系统错误
                break;
        }
        return reason;
    }

    //鉴权结果打印中文
    private String checkInfo(String si){
        String str;
        switch (si){
            case "5001":
                str = "无效卡号";
                break;
            case "5003":
                str = "余额不足";
                break;
            case "5004":
                str = "卡锁住";
                break;
            case "5007":
                str = "无效卡";
                break;
            case "5011":
                str = "套餐余额不足";
                break;
            case "5015":
                str = "无效账户状态";
                break;
            case "5016":
                str = "无效账户状态";
                break;
            case "5017":
                str = "密码错误一次";
                break;
            case "5018":
                str = "密码错误两次";
                break;
            case "5019":
                str = "密码错误三次";
                break;
            case "5099":
                str = "系统错误";
                break;
            default:
                str = "成功";
        }
        return str;
    }

}
